package org.budo.support.lang.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

/**
 * @author limingwei
 * @date 2016年6月4日 下午2:30:25
 */
@Slf4j
public class ListUtil {
    /**
     * 将一个集合分割成多个集合，限制分割后每个集合的大小
     * 
     * @param src
     * @param subSize 分割后的子集合的最大长度
     */
    public static <T> List<List<T>> splitBySize(List<T> src, Integer subSize) {
        if (null == src) {
            return null;
        }

        if (null == subSize || subSize < 1) {
            throw new IllegalArgumentException("#29 subSize must > 1, subSize=" + subSize);
        }

        if (src.isEmpty()) {
            return new ArrayList<List<T>>();
        }

        List<List<T>> dest = new ArrayList<List<T>>();

        int srcSize = src.size();
        int fromIndex = 0;
        int toIndex = subSize;

        while (true) {
            if (fromIndex >= srcSize) {
                break;
            }

            List<T> subList = subList(src, fromIndex, toIndex);
            dest.add(subList);

            fromIndex += subSize;
            toIndex += subSize;
        }

        return dest;
    }

    public static <T> List<T> subList(List<T> list, Integer fromIndex) {
        if (null == list || null == fromIndex) {
            throw new IllegalArgumentException("#62 list=" + list + ", fromIndex=" + fromIndex);
        }

        return subList(list, fromIndex, list.size());
    }

    public static <T> List<T> subList(List<T> list, Integer fromIndex, Integer toIndex) {
        if (null == list || null == fromIndex || null == toIndex) {
            throw new IllegalArgumentException("#70 list=" + list + ", fromIndex=" + fromIndex + ", toIndex=" + toIndex);
        }

        if (fromIndex < 0) {
            fromIndex = 0;
        }

        int size = list.size();
        if (toIndex > size) {
            toIndex = size;
        }

        if (fromIndex == 0 && toIndex == size) {
            return list;
        }

        return list.subList(fromIndex, toIndex);
    }

    /**
     * 会跳过空的元素
     */
    public static <T> List<T> arrayToList(T[] array) {
        if (null == array) {
            return null;
        }

        List<T> list = new ArrayList<T>();
        for (T each : array) {
            if (null != each) {
                list.add(each);
            }
        }
        return list;
    }

    /**
     * 会跳过空的元素
     */
    public static <T> List<T> toList(T... array) {
        if (null == array) {
            return null;
        }

        List<T> list = new ArrayList<T>();
        for (T each : array) {
            if (null != each) {
                list.add(each);
            }
        }
        return list;
    }

    public static <T> List<String> toStringList(T... array) {
        if (null == array) {
            return null;
        }

        List<String> list = new ArrayList<String>();
        for (T each : array) {
            if (null == each) {
                list.add(null);
            } else {
                list.add(each.toString());
            }
        }
        return list;
    }

    public static <T> List<T> append(List<T> list, T item) {
        if (null == list) {
            list = new ArrayList<T>();
        }
        list.add(item);
        return list;
    }

    public static <T> List<T> concat(List<T>... lists) {
        List<T> list = new ArrayList<T>();
        if (null != lists) {
            for (List<T> each : lists) {
                if (!isNullOrEmpty(each)) {
                    list.addAll(each);
                }
            }
        }
        return list;
    }

    public static Boolean isNullOrEmpty(List<?> list) {
        return null == list || list.isEmpty();
    }

    /**
     * 判断空值并防止越界
     */
    public static <T> T getItem(List<T> list, Integer index) {
        return getItem(list, index, null);
    }

    public static <T> T getItem(List<T> list, Integer index, T defaultValue) {
        boolean _default = null == list || null == index || index < 0 || index >= list.size();
        return _default ? defaultValue : list.get(index);
    }

    public static Integer size(List<?> list) {
        return null == list ? null : list.size();
    }

    public static <T> List<T> newList(Collection<T> collection) {
        if (null == collection) {
            return null;
        }
        return new ArrayList<T>(collection);
    }

    public static <T> T first(List<T> list) {
        return getItem(list, 0);
    }

    public static <T> T last(List<T> list) {
        return (null == list || list.isEmpty()) ? null : list.get(list.size() - 1);
    }

    public static <T> List<T> remove(List<T> list, T... remove) {
        List<T> result = new ArrayList<T>();
        for (T each : list) {
            if (!ArrayUtil.contains(remove, each)) {
                result.add(each);
            }
        }
        return result;
    }

    public static <T> List<T> enumerationToList(Enumeration<T> enumeration) {
        if (null == enumeration) {
            return null;
        }

        List<T> list = new ArrayList<T>();
        while (enumeration.hasMoreElements()) {
            T each = enumeration.nextElement();
            list.add(each);
        }
        return list;
    }

    public static <T> List<T> iteratorToList(Iterator<T> iterator) {
        if (null == iterator) {
            return null;
        }

        List<T> list = new ArrayList<T>();
        while (iterator.hasNext()) {
            T each = iterator.next();
            list.add(each);
        }
        return list;
    }

    public static <T> void addAll(Collection<T> to, Collection<T> from) {
        if (null == to || null == from) {
            log.warn("#192 to=" + to + ", from=" + from);
            return;
        }

        to.addAll(from);
    }

    /**
     * 将传入的list 复制一份 倒序后返回
     */
    public static <T> List<T> reverse(List<T> list) {
        if (null == list || list.isEmpty()) {
            return list;
        }

        List<T> newList = new ArrayList<T>(list);
        Collections.reverse(newList);
        return newList;
    }

    @SuppressWarnings("unchecked")
    public static <T> List<List<T>> partition(List<T> list, Integer size) {
        if (null == list || null == size //
                || size < 1 //
                || list.size() <= size) {
            return toList(list);
        }

        List<List<T>> result = new ArrayList<List<T>>();
        for (int i = 0; i < list.size(); i = i + size) {
            int toIndex = i + size;
            List<T> subList = subList(list, i, toIndex);
            result.add(subList);
        }
        return result;
    }

    public static <T> List<T> duplicate(T each, Integer count) {
        List<T> list = new ArrayList<T>();
        for (int i = 0; i < count; i++) {
            list.add(each);
        }
        return list;
    }

    public static <T> List<T> shuffle(List<T> list) {
        if (null == list || list.size() < 2) {
            return list;
        }

        Collections.shuffle(list);
        return list;
    }
}